<?php
namespace libraries\common;

defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * Request Condition Parser Trait
 *
 * @desc    前端筛选 -> Conditions：从请求解析 Conditions, 提供相关方法，具体定制的话可在子类中新增或覆盖
 * @version 1.0.0
 * @author  Jason
 * @date	2017年7月14日 下午7:38:17
 */
trait ConditionParser
{
	
	/**
	 * 从请求中提取查询、筛选和排序条件
	 * 
	 * @desc    从请求中提取查询、筛选和排序条件，需要请求中有 "conditions" 的参数，如果没有返回空数组。
	 * @author  Jason
	 * @date    2017年6月29日 下午4:46:13
	 * 
	 * @paramRequest   JSONString conditions 通用条件JSON字符串
	 * logical expression bitwise
	 * 						eg:
	 * {"where_and": [
	 * {"operator":"like","field":"name","value":"segwa","modifier":"raw"},
	 * {"operator":"bitwise","field":"status","value":["enabled","checked"],"modifier":"status_tags"},
	 * {"operator":"in","field":"member_id","value":"username","modifier":"foreign_member_name"},
	 * {"operator":"in","field":"merchant_id","value":[106,108],"modifier":"raw"},
	 * {"operator":"eq","field":"touroute_id","value":"45","modifier":"raw"},
	 * {"operator":"gt","field":"create_time","value":"2016-12-31 23:59:59","modifier":"time_string"},
	 * {"operator":"lt","field":"create_time","value":"2017-06-29 12:23:34","modifier":"time_string"},
	 * {"operator":"ge","field":"retail_price","value":"1000","modifier":"raw"},
	 * {"operator":"le","field":"retail_price","value":"1999","modifier":"raw"}
	 * ],
	 * "order_by": [
	 * {"field":"duration","direction":"DESC"},
	 * {"field":"price","direction":"ASC"}
	 * ]}
	 *
	 * @return  array	conditions 返回模型可用的 conditions 数组，并把原始 JSON 放到模板变量里面去。
	 */
	public function get_conditions()
	{
		$JSON = $this->CI->input->get_post('conditions');
		$this->CI->load->vars('conditions', $JSON);
		
		$array = json_decode($JSON, true);
		$array['where_and'] = isset($array['where_and']) ? $array['where_and'] : [];
		$array['order_by'] = isset($array['order_by']) ? $array['order_by'] : [];
		
		$conditions = [];
		foreach ($array['where_and'] as $where) {
			// MARK GetConditionsLibrary 把循环体中的逻辑抽离成函数
			$condition = $this->condition_component($where);
			#if (is_null($condition)) continue;
			if (!is_null($condition)) {
				$conditions[] = $condition;
			}
		}
		
		foreach ($array['order_by'] as $orderby) {
			$conditions[] = ['order_by', [$orderby['field'], $orderby['direction']]];
		}
		
		return $conditions;
	}
	
	protected function condition_component($where)
	{
		$condition = NULL;
		if(!isset($where['operator']) || !isset($where['field']) || !isset($where['value'])) {
			return $condition;
		}
		
		$where['modifier'] = isset($where['modifier']) ? $where['modifier'] : 'raw';
		$modifier_parser = [$this, "condition_component_parse_modifier_{$where['modifier']}"];
		if (!is_callable($modifier_parser)) {
			log_message('error', sprintf("The Modifier '%s' of Condition '%s' is NOT supported!", $where['modifier'], var_export($where, true)));
			return $condition;
		}
		
		switch ($where['operator']) {
			case 'like':
				// modifier==raw
				$condition = ['like', [$where['field'], $where['value']]];
				break;
			case 'bitwise':
				$sub_where = call_user_func_array($modifier_parser, [$where['value']]);
				$condition = ['where', $sub_where];
				break;
			case 'in':
				$where['value'] = call_user_func_array($modifier_parser, [$where['value']]);
				// MARK MARK MARK 找到一个好的方法来处理 IN() 的问题！
				// MARK MARK MARK 使用一个优雅的方法来解决 CI DB IN 值为空()时报错的问题！
				// MARK MARK MARK -1?No! -9999?No! ''?No! No! No No No!
				// MARK MARK MARK 答案：MySQL 里面 NULL 需要判断 IS NULL，所以使其 IN(NULL) 是个不错的选择！
				if (empty($where['value'])) {
					$where['value'] = [NULL];
				}
				$condition = ['where_in', [$where['field'], $where['value']]];
				break;
			case 'lt':
			case 'le':
			case 'eq':
			case 'ge':
			case 'gt':
				$where['value'] = call_user_func_array($modifier_parser, [$where['value']]);
				$operator = $this->condition_component_parse_operator_comparison($where['operator']);
				/*
				 * // MARK 修复 ConditionParser 数据库发生错误。
								当 Operator 为 lt/le/eq/ge/gt 并且 value 为字符串形式的值的情况下，会发生数据库错误。
					 Error Number: 1054
						Unknown column 'member' in 'where clause'
						SELECT COUNT(*) AS `numrows` FROM `tag` WHERE `module` = `member`
						Filename: core/MY_Model.php
						Line Number: 410
				 */
				$condition = ['where', "`{$where['field']}` {$operator} '{$where['value']}'"];
				break;
			default:
				log_message('error', sprintf("The Operator '%s' of Condition '%s' is NOT supported!", $where['operator'], var_export($where, true)));
		}
		
		return $condition;
	}
	
	protected function condition_component_parse_operator_comparison($operator)
	{
		$operator = str_replace(['l', 'e', 'g', 'q', 't'], ['<', '=', '>', '', ''], $operator);
		return $operator;
	}
	
	protected function condition_component_parse_modifier_raw($value)
	{
		return $value;
	}
	
	protected function condition_component_parse_modifier_status_tags($value)
	{
		$mod_component = str_replace('Lib_', 'mod_', get_class());
		// MARK 这里应该需要加上 $mapping 参数
		$where =  $this->$mod_component->calculate_status_condition_where($value);
		return $where;
	}
	
	/**
	 * 先按照某一字段(name)从某一外表(member)中查找出精确匹配的 id 列表，然后再用于 in 条件
	 * 
	 * @param string $value
	 * 
	 * @return array
	 */
	protected function condition_component_parse_modifier_foreign_member_name($value)
	{
		$this->CI->load->model('mod_member');
		$conditions = [
				['select', 'id'],
				#['like', ['name', $value]],
				['where', ['name', $value]],
		];
		$value = $this->CI->mod_member->select_instances_by_conditions($conditions);
		$value = array_column($value, 'id');
		return $value;
	}
	
	protected function condition_component_parse_modifier_time_string($value)
	{
		$value = strtotime($value);
		return $value;
	}
	
}
